home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / rdcf.exe / CACHE.C < prev    next >
C/C++ Source or Header  |  1993-01-15  |  4KB  |  176 lines

  1. /* Reentrant Cache System 1.1 */
  2.  
  3. #include "cache.h"
  4. #include <alloc.h>
  5. #include <mem.h>
  6.  
  7. enum buffer_status {EMPTY, CLEAN, DIRTY};
  8.  
  9. static unsigned access(struct cache *q, int write, struct cache_block *b)
  10. {
  11.   unsigned e = (*q->drive_access)(write, b->drive, b->sector, b->data);
  12.   if (e!=0)
  13.   {
  14.     q->error_sector = b->sector;
  15.     q->error_drive = b->drive;
  16.   }
  17.   return e;
  18. }
  19.  
  20. unsigned cache_access(struct cache *q, int write, unsigned drive,
  21.   unsigned sector, void *buffer)
  22. {
  23.   struct
  24.   {
  25.     struct cache_block *previous;
  26.     struct cache_block *current;
  27.   } b, empty, clean, dirty;
  28.   /* find the matching block, and also the first empty, clean and dirty  */
  29.   /* blocks, all with a single pass through the list                     */
  30.   b.previous = empty.current = clean.current = dirty.current = NULL;
  31.   b.current = q->first;
  32.   do
  33.   {
  34.     if (b.current->status == EMPTY)
  35.     {
  36.       if (empty.current == NULL) empty = b;
  37.     }
  38.     else if (b.current->sector == sector && b.current->drive == drive)
  39.       break;
  40.     else
  41.     {
  42.       if (b.current->status == CLEAN)
  43.       {
  44.         if (clean.current == NULL) clean = b;
  45.       }
  46.       else if (dirty.current == NULL) dirty = b;
  47.     }
  48.     b.previous = b.current;
  49.     b.current = b.current->next;
  50.   } while (b.current != NULL);
  51.   /* if there is no matching block, assign one according to the rules */
  52.   if (b.current == NULL)
  53.   {
  54.     if (empty.current != NULL) {b = empty; q->empty--;}
  55.     else if (clean.current != NULL) {b = clean; q->clean--;}
  56.     else
  57.     {
  58.       unsigned e;
  59.       b = dirty;
  60.       e = access(q, 1, b.current);
  61.       if (e) return e;
  62.       q->dirty--;
  63.     }
  64.     b.current->status = EMPTY;
  65.     b.current->sector = sector;
  66.     b.current->drive = drive;
  67.     q->empty++;
  68.   }
  69.   if (write)
  70.   {
  71.     if (b.current->status == EMPTY) {q->empty--; q->dirty++;}
  72.     else if (b.current->status == CLEAN) {q->clean--; q->dirty++;}
  73.     memcpy(b.current->data, buffer, q->sector_size);
  74.     b.current->status = DIRTY;
  75.   }
  76.   else 
  77.   {
  78.     if (b.current->status == EMPTY)
  79.     {
  80.       unsigned e = access(q, 0, b.current);
  81.       if (e) return e;
  82.       q->empty--;
  83.       q->clean++;
  84.       b.current->status = CLEAN;
  85.     }
  86.     memcpy(buffer, b.current->data, q->sector_size);
  87.   }
  88.   /* put block at the end of the line */
  89.   if (b.current != q->last)
  90.   {
  91.     if (b.previous == NULL) q->first = b.current->next;
  92.     else b.previous->next = b.current->next;
  93.     q->last->next = b.current;
  94.     b.current->next = NULL;
  95.     q->last = b.current;
  96.   }
  97.   return 0;
  98. }
  99.  
  100. unsigned cache_flush_and_or_clear(struct cache *q, int drive, int options)
  101. {
  102.   unsigned return_value = 0;
  103.   struct cache_block *b;
  104.   for (b=q->first; b!=NULL; b=b->next)
  105.   {
  106.     if (drive<0 || b->drive==drive)
  107.     {
  108.       if (options&CACHE_FLUSH && b->status==DIRTY)
  109.       {
  110.         unsigned e = access(q, 1, b);
  111.         if (e) return_value = e;
  112.         b->status = CLEAN;
  113.         q->dirty--;
  114.         q->clean++;
  115.       }
  116.       if (options&CACHE_CLEAR)
  117.       {
  118.         if (b->status == CLEAN)
  119.         {
  120.           q->clean--;
  121.           q->empty++;
  122.         }
  123.         else if (b->status == DIRTY)
  124.         {
  125.           q->dirty--;
  126.           q->empty++;
  127.         }
  128.         b->status = EMPTY;
  129.       }
  130.     }
  131.   }
  132.   return return_value;
  133. }
  134.  
  135. void cache_free(struct cache *q)
  136. {
  137.   struct cache_block *b = q->first;
  138.   while (b!=NULL)
  139.   {
  140.     struct cache_block *next = b->next;
  141.     free(b);
  142.     b = next;
  143.   }
  144.   free(q);
  145. }
  146.  
  147. struct cache *cache_initialize(unsigned (*drive_access)(int, unsigned,
  148.   unsigned, void *), unsigned number_of_sectors, unsigned sector_size)
  149. {
  150.   struct cache *q = malloc(sizeof(struct cache));
  151.   if (q!=NULL)
  152.   {
  153.     struct cache_block *b;
  154.     q->empty = number_of_sectors;
  155.     b = q->first = malloc(sizeof(struct cache_block)+sector_size-1);
  156.     while (1)
  157.     {
  158.       if (b==NULL)
  159.       {
  160.         cache_free(q);
  161.         return NULL;
  162.       }
  163.       b->status = EMPTY;
  164.       if (--number_of_sectors == 0) break;
  165.       b = b->next = malloc(sizeof(struct cache_block)+sector_size-1);
  166.     }
  167.     b->next = NULL;
  168.     q->last = b;
  169.     q->drive_access = drive_access;
  170.     q->sector_size = sector_size;
  171.     q->clean = q->dirty = 0;
  172.   }
  173.   return q;
  174. }
  175.  
  176.